home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Toolbox / Balloony / Balloonify.c next >
Encoding:
C/C++ Source or Header  |  1997-10-16  |  20.3 KB  |  897 lines  |  [TEXT/KAHL]

  1. /* Balloonify.c - this is the meat of this program.
  2.     pseudo code:
  3.         • open input file
  4.         • create output file.
  5.         • open output file
  6.         • BalloonifyMenus
  7.         BalloonifyDialogs
  8.         • close output file
  9.         • close input file
  10.         
  11.     November 11, 1996: I, David Phillip Oster, place this source code in the public
  12.         domain. This means you can do anyhing you want with it.
  13.     It would be considerate if you kept me posted on any bugs, bug fixes, or
  14.     improvements.
  15.     oster@netcom.com
  16.  */
  17. #include <stdlib.h>
  18. #include <Balloons.h>
  19. #include "Balloonify.h"
  20. #include "BalloonyRes.h"
  21.  
  22. /* DitlItemRec - this actually varies in size, so don't use sizeof of it.
  23.     an item in a DITl resource.
  24.     used for functions that probe a DITl resource
  25.  */
  26. typedef struct DitlItemRec {
  27.     LongInt    handOrPtr;
  28.     Rect    r;
  29.     char    type;
  30.     char    len;
  31.     Integer    resID;    /* present only in control items. */
  32. }DitlItemRec, *DitlItemPtr;
  33.  
  34. /* A CNTL resource - used for functions that probe a CNTL resource
  35.  */
  36. typedef struct CtlItemRec {
  37.     Rect    r;
  38.     Integer    val;
  39.     Integer    vis;
  40.     Integer    max;
  41.     Integer    min;
  42.     Integer    procId;
  43.     LongInt    refCon;
  44.     Str255    title;    
  45. }CtlItemRec, *CtlItemPtr, **CtlItemHandle;
  46.  
  47. static StringPtr wild1S;
  48. static StringPtr wild2S;
  49. static StringPtr wild3S;
  50. static StringPtr minusS;
  51. static StringPtr oneS;
  52. static StringPtr commaReturnS;
  53. static StringPtr commaS;
  54. static StringPtr hS;
  55. static StringPtr menuS;
  56. static StringPtr hmnuS;
  57. static StringPtr cntlS;
  58. static StringPtr buttonS;
  59. static StringPtr checkBoxS;
  60. static StringPtr radioButtonS;
  61. static StringPtr textS;
  62. static StringPtr editS;
  63. static StringPtr iconS;
  64. static StringPtr pictS;
  65. static StringPtr userS;
  66. static StringPtr unknownS;
  67. static StringPtr ditlS;
  68. static StringPtr hdlgS;
  69.  
  70. static StringPtr *initStrs[] = {
  71.     &wild1S,
  72.     &wild2S,
  73.     &wild3S,
  74.     &minusS,
  75.     &oneS,
  76.     &commaReturnS,
  77.     &commaS,
  78.     &hS,
  79.     &menuS,
  80.     &hmnuS,
  81.     &cntlS,
  82.     &buttonS,
  83.     &checkBoxS,
  84.     &radioButtonS,
  85.     &textS,
  86.     &editS,
  87.     &iconS,
  88.     &pictS,
  89.     &userS,
  90.     &unknownS,
  91.     &ditlS,
  92.     &hdlgS,
  93.     NIL
  94. };
  95.  
  96. /* InitBalloonify - initialize the string pointers
  97.  */
  98. void InitBalloonify(void){
  99.     StringPtr    **spp;
  100.     StringPtr    *sp;
  101.     StringPtr    p;
  102.     Handle        h;
  103.  
  104.     h = GetResource('STR#', kSmallStrs);
  105.     DetachResource(h);
  106.     HLock(h);
  107.     HNoPurge(h);
  108.     p = (StringPtr) (sizeof(Integer) + *h);
  109.     for(spp = initStrs; NIL != *spp ; spp++){
  110.         sp = *spp;
  111.         *sp = p;
  112.         p += Length(p) + 1;
  113.     }
  114. }
  115.  
  116. /* *** sort functions
  117.  */
  118.  
  119. typedef struct SortResRec{
  120.     LongInt    id;
  121.     Handle    h;
  122. }SortResRec, *SortResPtr, **SortResHandle;
  123.  
  124. /* NewSortArray - sort in increasing id order.
  125.  */
  126. static SortResHandle    NewSortArray(Integer size){
  127.     return (SortResHandle) NewHandleClear(size * (LongInt) sizeof(SortResRec));
  128. }
  129.  
  130. /* CompareResRec - comparison function for qsort.
  131.     Treat negative numbers as greater than any positive number
  132.  */
  133. static int CompareResRec(const void * a, const void *b){
  134.     return (unsigned) ((SortResPtr) a)->id - (unsigned) ((SortResPtr) b)->id;
  135. }
  136.  
  137. /* NewSortedRes - gather all the resources of a particular type from the
  138.     current resource file, and return them (unloaded) in an array.
  139.     Note: resource files can only hold ~2000 items, so shorts==Integers are safe here.
  140.  */
  141. static OSErr NewSortedRes(OSType type, SortResHandle *srhp){
  142.     OSErr    errCode;
  143.     Integer    i, max, id;
  144.     SortResHandle    srh;
  145.     Handle    h;
  146.     Str255    name;
  147.  
  148.     errCode = noErr;
  149.     max = Count1Resources(type);
  150.     if(NIL == (srh = NewSortArray(max))){
  151.         return memFullErr;
  152.     }
  153.  
  154.     /* fill in the array
  155.      */
  156.     SetResLoad(FALSE);
  157.     for(i = 1 ; i <= max && noErr == errCode ; i++){
  158.         if(NIL != (h = Get1IndResource(type, i))){
  159.             HPurge(h);
  160.             GetResInfo(h, &id, &type, name);
  161.             (*srh)[i-1].h    = h;
  162.             (*srh)[i-1].id    = id;
  163.         }
  164.     }
  165.     SetResLoad(TRUE);
  166.     if(noErr != errCode){
  167.         if(NIL != srh){
  168.             DisposeHandle((Handle) srh);
  169.             srh = NIL;
  170.         }
  171.         return errCode;
  172.     }
  173.  
  174.      /* shrink to the size actually gathered.
  175.       */
  176.     if(max != i-1){
  177.         max = i-1;
  178.         SetHandleSize((Handle)srh, sizeof(SortResRec)*max);
  179.     }
  180.  
  181.     /* sort the array
  182.      */
  183.     if(max > 1){
  184.         HLock((Handle) srh);
  185.         qsort(*srh, max, sizeof(SortResRec), CompareResRec);
  186.         HUnlock((Handle) srh);
  187.     }
  188.     *srhp = srh;
  189.     return errCode;
  190. }
  191.  
  192. /* *** i/o functions.
  193.  */
  194.  
  195.  
  196. /* FSWriteStr - write a pascal string to the output
  197.  */
  198. static OSErr FSWriteStr(Integer outRef, const StringPtr s){
  199.     LongInt    len;
  200.  
  201.     len = Length(s);
  202.     return FSWrite(outRef, &len, &s[1]);
  203. }
  204.  
  205. /* WriteStrSharp - write an entire STR# to the standard output doing pattern replacement as you go.
  206.  */
  207. static OSErr WriteStrSharp(Integer strsNum, const StringPtr s1, const StringPtr s2, const StringPtr s3, Integer outRef){
  208.     OSErr    errCode;
  209.     Integer i, max;
  210.     Handle    h;
  211.     Str255    s;
  212.  
  213.     errCode = noErr;
  214.     if(NIL != (h = GetResource('STR#', strsNum))){
  215.         max = ** (Integer **) h;
  216.         for(i = 1 ; i <= max && noErr == errCode; i++){
  217.             GetIndString(s, strsNum, i);
  218.             if(EqualString(s, wild1S, FALSE, FALSE)){
  219.                 errCode = FSWriteStr(outRef, s1);
  220.             }else if(EqualString(s, wild2S, FALSE, FALSE)){
  221.                 errCode = FSWriteStr(outRef, s2);
  222.             }else if(EqualString(s, wild3S, FALSE, FALSE)){
  223.                 errCode = FSWriteStr(outRef, s3);
  224.             }else{
  225.                 errCode = FSWriteStr(outRef, s);
  226.             }
  227.         }
  228.     }else{
  229.         return resNotFound;
  230.     }
  231.     return errCode;
  232. }
  233.  
  234. /* BalloonifyHeader - dump out the file header.
  235.  */
  236. static OSErr BalloonifyHeader(StringPtr name, Integer outRef){
  237.     return WriteStrSharp(kHeaderStrs, name, emptyS, emptyS, outRef);
  238. }
  239.  
  240. static Integer CountMTItems(const Handle h){
  241.     return CountMItems((MenuHandle) h);
  242. }
  243.  
  244. /* GetTItem - retrieve an item from a menuhandle 0 is the title.
  245.  */
  246. static void GetTItem(const Handle h, Integer i, StringPtr s){
  247.     if(0 == i){
  248.         StrMove( (**(MenuHandle) h).menuData, s);
  249.     }else{
  250.         GetItem((MenuHandle) h, i, s);
  251.     }
  252. }
  253.  
  254. /* IsSkipItem - TRUE if we should skip this item.
  255.  */
  256. static Boolean IsSkipItem(const StringPtr s){
  257.     return Length(s) == 0 || 
  258.         EqualString(minusS, s, FALSE, FALSE) ||
  259.         EqualString("\p\0", s, FALSE, FALSE);
  260. }
  261.  
  262.  
  263. /* Stringify - 
  264.  */
  265. static void Stringify(const StringPtr itemS, StringPtr s){
  266.     Integer    i;
  267.  
  268.     s[0] = 0;
  269.     for(i = 1 ; i <= Length(itemS); i++){
  270.         switch(itemS[i]){
  271.         case '\0':
  272.         case '\1':
  273.         case '\2':
  274.         case '\3':
  275.         case '\4':
  276.         case '\5':
  277.         case '\6':
  278.         case '\7':
  279.             AppendChar(s, '\\');
  280.             AppendChar(s, itemS[i] + '0');
  281.             break;
  282.         case '\b':
  283.             AppendChar(s, '\\');
  284.             AppendChar(s, 'b');
  285.             break;
  286.         case '\t':
  287.             AppendChar(s, '\\');
  288.             AppendChar(s, 't');
  289.             break;
  290.         case '\n':
  291.         case '\r':
  292.             AppendChar(s, '\\');
  293.             AppendChar(s, 'n');
  294.             break;
  295.         case '"':
  296.         case '\\':
  297.             AppendChar(s, '\\');
  298.             AppendChar(s, itemS[i]);
  299.             break;
  300.         default:
  301.             AppendChar(s, itemS[i]);
  302.             break;
  303.         }
  304.         
  305.     }
  306. }
  307.  
  308.  
  309. /* WriteStrItem - write an item to a STR#. mostly just a numericly labeled comma separated string
  310.  */
  311. static OSErr WriteStrItem(const StringPtr itemS, const StringPtr nameS, const StringPtr helpStrsS, const StringPtr nS, Integer outRef){
  312.     OSErr    errCode;
  313.     Str255    s;
  314.  
  315.     errCode = noErr;
  316.     if(IsSkipItem(itemS)){
  317.         return errCode;
  318.     }
  319.     if(NOT EqualString(oneS, nS, FALSE, FALSE)){    /* not first item, put a comma */
  320.         errCode = FSWriteStr(outRef, commaReturnS);
  321.     }
  322.     if(noErr == errCode){ errCode = WriteStrSharp(kRepeatStrs, nameS, helpStrsS, nS, outRef); }
  323.     Stringify(itemS, s);
  324.     AppendChar(s, '"');
  325.     if(noErr == errCode){ errCode = FSWriteStr(outRef, s); }
  326.     return errCode;
  327. }
  328.  
  329.  
  330. /* WriteHmnuMenuItem - write an item to an hmnu resource
  331.  */
  332. static OSErr WriteHmnuMenuItem(const StringPtr itemS, const StringPtr menuS, const StringPtr helpStrsS, const StringPtr nS, Integer outRef){
  333.     OSErr    errCode;
  334.     Str255    s;
  335.  
  336.     if(NOT EqualString(oneS, nS, FALSE, FALSE)){    /* not first item, put a comma */
  337.         if(noErr != (errCode = FSWriteStr(outRef, commaS))){
  338.             return errCode;
  339.         }
  340.     }
  341.     if(IsSkipItem(itemS)){
  342.         GetIndString(s, kMainStrs, kSkipItemS);
  343.         return FSWriteStr(outRef, s);
  344.     }else{
  345.         return WriteStrSharp(kHMNUStringResStrs, menuS, helpStrsS, nS, outRef);
  346.     }
  347. }
  348.  
  349. /* StripNonAlphaNum - strip non alphanumeric characters from the string.
  350.  */
  351. static void StripNonAlphaNum(StringPtr menuS){
  352.     Str255    s;
  353.     Integer    i;
  354.  
  355.     s[0] = 0;
  356.     for(i = 1 ; i <= Length(menuS); i++){
  357.         if(('0' <= menuS[i] && menuS[i] <= '9') ||
  358.             ('a' <= menuS[i] && menuS[i] <= 'z') ||
  359.             ('A' <= menuS[i] && menuS[i] <= 'Z') ||
  360.             '_' == menuS[i]){
  361.  
  362.             AppendChar(s, menuS[i]);
  363.         }
  364.     }
  365.     StrMove(s, menuS);
  366. }
  367.  
  368.  
  369. /* GetMenuName - get a plausible name for this menu.
  370.  */
  371. static void GetMenuName(const Handle h, StringPtr menuS){
  372.     Integer    id;
  373.     OSType    type;
  374.     Str255    nS;
  375.  
  376.     GetResInfo(h, &id, &type, menuS);
  377.     if(0 == Length(menuS)){
  378.         GetTItem(h, 0, menuS);
  379.     }
  380.     StripNonAlphaNum(menuS);
  381.     if(0 == Length(menuS)){
  382.         NumToString(id, nS);
  383.         if('-' == nS[1]){
  384.             nS[1] = 'm';
  385.         }
  386.         StrMove(hS, menuS);
  387.         Concat(menuS, nS);
  388.     }
  389. }
  390.  
  391.  
  392. /* BalloonifyMenu1 - put out the menu
  393.     1.) collect the replacement strings.
  394.     2.) dump out the initial header
  395.     3.) loop through the items
  396.     4.) dump out the midedial header
  397.     5.) loop through the items
  398.     6.) dump out the closer.
  399.  */
  400. static OSErr BalloonifyMenu1(Handle h, Integer outRef){
  401.     OSErr    errCode;
  402.     Str255    nameS;
  403.     Str255    helpStrsS;
  404.     Str255    itemS;
  405.     Str255    idS;
  406.     Str255    nS;
  407.     Integer    i, j, max, id;
  408.     OSType    type;
  409.  
  410.     errCode = noErr;
  411.     nameS[0] = helpStrsS[0] = itemS[0] = nS[0] = '\0';
  412.  
  413.     /* 1.) collect the replacement strings.
  414.      */
  415.     GetMenuName(h, nameS);
  416.     StrMove(nameS, helpStrsS);
  417.     errCode = BumpProgress(nameS);
  418.     Concat(nameS, menuS);
  419.     Concat(helpStrsS, hmnuS);
  420.  
  421.     /* 2.) dump out the initial header
  422.      */
  423.     GetResInfo(h, &id, &type, idS);
  424.     NumToString(id, idS);
  425.     if(noErr == errCode){ errCode = WriteStrSharp(kHMNUNormal1Strs, nameS, helpStrsS, idS, outRef); }
  426.     /* 3.) loop through the items
  427.      */
  428.     max = CountMTItems(h);
  429.     for(i = 0, j = 1 ; i <= max && noErr == errCode; i++){
  430.         NumToString(j, nS);
  431.         GetTItem(h, i, itemS);
  432.         if(NOT (IsSkipItem(itemS))){
  433.             errCode = WriteStrItem(itemS, nameS, helpStrsS, nS, outRef);
  434.             j++;
  435.         }
  436.     }
  437.  
  438.     /* 4.) dump out the medial header
  439.      */
  440.     if(noErr == errCode){ errCode = WriteStrSharp(kHMNUMedialStrs, nameS, helpStrsS, nS, outRef); }
  441.  
  442.     /* 5.) loop through the items
  443.      */
  444.     for(i = 0, j = 1; i <= max && noErr == errCode; i++){
  445.         NumToString(j, nS);
  446.         GetTItem(h, i, itemS);
  447.         errCode = WriteHmnuMenuItem(itemS, nameS, helpStrsS, nS, outRef);
  448.         if(NOT (IsSkipItem(itemS))){
  449.             j++;
  450.         }
  451.     }
  452.  
  453.     /* 6.) dump out the closer.
  454.      */
  455.     if(noErr == errCode){ errCode = WriteStrSharp(kHMNUCloseStrs, nameS, helpStrsS, nS, outRef); }
  456.     return errCode;
  457. }
  458.  
  459.  
  460. /* BalloonifyMenus - for each menu, write the menu's STR#.  write the menu's 'hmnu'
  461.     sorts the menus.
  462.  */
  463. static OSErr BalloonifyMenus(Integer inRes, Integer outRef){
  464.     OSErr    errCode;
  465.     Integer    i, max;
  466.     Integer saveResFile;
  467.     Handle    h;
  468.     SortResHandle    srh;
  469.  
  470.     errCode = noErr;
  471.     saveResFile = CurResFile();
  472.     UseResFile(inRes);
  473.  
  474.     /* get the sorted resources.
  475.      */
  476.     if(noErr != (errCode = NewSortedRes('MENU', &srh))){
  477.         return errCode;
  478.     }
  479.     max = GetHandleSize((Handle) srh) / sizeof(SortResRec);
  480.  
  481.  
  482.     /* process the sorted menus.
  483.      */
  484.     for(i = 0; i < max && noErr == errCode ; i++){
  485.         h = (*srh)[i].h;
  486.         LoadResource(h);
  487.         if(noErr != (errCode = ResError())){
  488.             break;
  489.         }
  490.         HNoPurge(h);
  491.         HLock(h);
  492.         UseResFile(saveResFile);
  493.         errCode = BalloonifyMenu1(h, outRef);
  494.         UseResFile(inRes);
  495.         ReleaseResource(h);
  496.     }
  497.     UseResFile(saveResFile);
  498.     if(NIL != srh){
  499.         DisposeHandle((Handle) srh);
  500.     }
  501.     return errCode;
  502. }
  503.  
  504. /* GetDlogName - gets a string name for the dialog.
  505.     1.) we try to get title from name of ditl resource
  506.     2.) we try to get title from name of associated dialog.
  507.     3.) we try to get title from windowName of assocaiated dialog.
  508.     4.) we just use the resource number.
  509.  
  510.     Note: as an optimization we check first for the DLOG with the same id as the
  511.         DITL. if that fails, we loop over them all.
  512.  */
  513. static void GetDlogName(const Handle h, Integer inRes, StringPtr dlogS){
  514.     Integer        saveRes;
  515.     Integer        id, did;
  516.     Integer        i, max;
  517.     OSType        type, dtype;
  518.     Str255        s;
  519.     DialogTHndl    dt;
  520.  
  521.     GetResInfo(h, &id, &type, dlogS);
  522.     if(0 == Length(dlogS)){
  523.         saveRes = CurResFile();
  524.         UseResFile(inRes);
  525.         if(NIL != (dt = (DialogTHndl) Get1Resource('DLOG', id)) && 
  526.             id == (**dt).itemsID){
  527.  
  528.             GetResInfo((Handle) dt, &did, &dtype, dlogS);
  529.             if(0 == Length(dlogS)){
  530.                 StrMove((**dt).title, dlogS);
  531.             }
  532.         }else{
  533.             max = Count1Resources('DLOG');
  534.             for(i = 1; i <= max ; i++){
  535.                 if(NIL != (dt = (DialogTHndl) Get1IndResource('DLOG', i)) &&
  536.                     id == (**dt).itemsID){
  537.  
  538.                     GetResInfo((Handle) dt, &did, &dtype, dlogS);
  539.                     if(0 == Length(dlogS)){
  540.                         StrMove((**dt).title, dlogS);
  541.                     }
  542.                     break;
  543.                 }    
  544.             }
  545.         }
  546.         UseResFile(saveRes);
  547.     }
  548.     StripNonAlphaNum(dlogS);
  549.     if(0 == Length(dlogS)){
  550.         NumToString(id, s);
  551.         if('-' == s[1]){
  552.             s[1] = 'm';
  553.         }
  554.         StrMove(hS, dlogS);
  555.         Concat(dlogS, s);
  556.     }
  557. }
  558.  
  559. /* CountTDItems - counts the number of items in the dialog template
  560.  */
  561. static Integer CountTDItems(const Handle h){
  562.     return 1 + **(Integer **) h;
  563. }
  564.  
  565.  
  566. /* SkipTDItem - skip an item in a DITL.
  567.  */
  568. static Integer SkipTDItem(const Handle h, LongInt off){
  569.     DitlItemPtr     dip;
  570.     Ptr                p;
  571.  
  572.     dip = (DitlItemPtr) ((*h) + off);
  573.     p = (Ptr) dip + sizeof(long) + sizeof(Rect) + 2 * sizeof(char) + dip->len;
  574.     if(((LongInt) p) & 1){
  575.         p++;
  576.     }
  577.     return p - *h;
  578. }
  579.  
  580. /* GetCitlItem - get the title out of the CNTL resource template
  581.  */
  582. static void GetCitlItem(Integer id, Integer inRes, StringPtr itemS){
  583.     Integer    saveResFile;
  584.     Handle    h;
  585.     OSType    type;
  586.  
  587.     saveResFile = CurResFile();
  588.     UseResFile(inRes);
  589.     if(NIL != (h = Get1Resource('CNTL', id))){
  590.         LoadResource(h);
  591.         StrMove( (** (CtlItemHandle) h).title, itemS);
  592.         if(0 == Length(itemS)){
  593.             GetResInfo(h, &id, &type, itemS);
  594.         }
  595.         HPurge(h);
  596.     }
  597.     UseResFile(saveResFile);
  598.     if(0 == Length(itemS)){
  599.         StrMove(cntlS, itemS);
  600.     }
  601. }
  602.  
  603. /* GetNonTextItem - get the title out of a non-text resource.
  604.  */
  605. static void GetNonTextItem(StringPtr defaultS, OSType type, Integer id, Integer inRes, StringPtr itemS){
  606.     Integer    saveResFile;
  607.     Handle    h;
  608.  
  609.     saveResFile = CurResFile();
  610.     UseResFile(inRes);
  611.     SetResLoad(FALSE);
  612.     if(NIL != (h = Get1Resource(type, id))){
  613.         GetResInfo(h, &id, &type, itemS);
  614.     }
  615.     SetResLoad(TRUE);
  616.     UseResFile(saveResFile);
  617.     if(0 == Length(itemS)){
  618.         StrMove(defaultS, itemS);
  619.     }
  620. }
  621.  
  622. /* GetTDItem - returns the 1s based item as a string in itemS
  623.  */
  624. static void GetTDItem(const Handle h, Integer i, Integer inRes, StringPtr itemS){
  625.     LongInt            offset;
  626.     DitlItemPtr     dip;
  627.     SignedByte        state;
  628.  
  629.     for(offset = sizeof(Integer) ; i > 1 ; i--){
  630.         offset = SkipTDItem(h, offset);
  631.     }
  632.     itemS[0] = '\0';    /* initialize */
  633.     state = HGetState((Handle) h);
  634.     HLock((Handle) h);
  635.     dip = (DitlItemPtr) ((*h) + offset);
  636.     switch(((unsigned char) dip->type) & ~itemDisable){
  637.     case helpItem:    
  638.         HSetState((Handle) h, state);    
  639.         return;    /* null string for this one */
  640.     case ctrlItem|btnCtrl:
  641.         StrMove((StringPtr) &dip->len, itemS);
  642.         if(0 == Length(itemS)){
  643.             StrMove(buttonS, itemS);
  644.         }
  645.         break;
  646.     case ctrlItem|chkCtrl:
  647.         StrMove((StringPtr) &dip->len, itemS);
  648.         if(0 == Length(itemS)){
  649.             StrMove(checkBoxS, itemS);
  650.         }
  651.         break;
  652.     case ctrlItem|radCtrl:
  653.         StrMove((StringPtr) &dip->len, itemS);
  654.         if(0 == Length(itemS)){
  655.             StrMove(radioButtonS, itemS);
  656.         }
  657.         break;
  658.     case statText:
  659.         StrMove((StringPtr) &dip->len, itemS);
  660.         if(0 == Length(itemS)){
  661.             StrMove(textS, itemS);
  662.         }
  663.         break;
  664.     case editText:
  665.         StrMove((StringPtr) &dip->len, itemS);
  666.         if(0 == Length(itemS)){
  667.             StrMove(editS, itemS);
  668.         }
  669.         break;
  670.     case ctrlItem|resCtrl:    GetCitlItem(dip->resID, inRes, itemS);    break;
  671.     case iconItem:    GetNonTextItem(iconS, 'ICON', dip->resID, inRes, itemS); break;
  672.     case picItem:    GetNonTextItem(pictS, 'PICT', dip->resID, inRes, itemS); break;
  673.     case userItem:    StrMove(userS, itemS); break;
  674.     default:    StrMove(unknownS, itemS); break;
  675.     }
  676.     HSetState((Handle) h, state);
  677. }
  678.  
  679. /* WriteHdlgDitlItem - write out an item to an hdlg resource.
  680.  */
  681. static OSErr WriteHdlgDitlItem(const StringPtr itemS, const StringPtr dlogS, const StringPtr helpStrsS, const StringPtr nS, Integer outRef){
  682.     Str255    s;
  683.     OSErr    errCode;
  684.  
  685.     if(NOT EqualString(oneS, nS, FALSE, FALSE)){    /* not first item, put a comma */
  686.         if(noErr != (errCode = FSWriteStr(outRef, commaS))){
  687.             return errCode;
  688.         }
  689.     }
  690.     if(IsSkipItem(itemS)){
  691.         GetIndString(s, kMainStrs, kSkipItemS);
  692.         return FSWriteStr(outRef, s);
  693.     }else{
  694.         return WriteStrSharp(kHDLGStringResStrs, dlogS, helpStrsS, nS, outRef);
  695.     }
  696. }
  697.  
  698.  
  699. /* BalloonifyDitl1 - put out the STR# and hdlg
  700.     1.) collect the replacement strings.
  701.     2.) dump out the initial header
  702.     3.) loop through the items
  703.     4.) dump out the midedial header
  704.     5.) loop through the items
  705.     6.) dump out the closer.
  706.  */
  707. static OSErr BalloonifyDitl1(Handle h, Integer inRes, Integer outRef){
  708.     OSErr    errCode;
  709.     Str255    dlogS;
  710.     Str255    helpStrsS;
  711.     Str255    itemS;
  712.     Str255    idS;
  713.     Str255    nS;
  714.     Integer    i, j, max, id;
  715.     OSType    type;
  716.  
  717.     errCode = noErr;
  718.     dlogS[0] = helpStrsS[0] = itemS[0] = nS[0] = '\0';
  719.  
  720.     /* 1.) collect the replacement strings.
  721.      */
  722.     GetDlogName(h, inRes, dlogS);
  723.     StrMove(dlogS, helpStrsS);
  724.     errCode = BumpProgress(dlogS);
  725.     Concat(dlogS, ditlS);
  726.     Concat(helpStrsS, hdlgS);
  727.  
  728.     /* 2.) dump out the initial header
  729.      */
  730.     GetResInfo(h, &id, &type, idS);
  731.     NumToString(id, idS);
  732.     if(noErr == errCode){ errCode = WriteStrSharp(kHDLGNormal1Strs, dlogS, helpStrsS, idS, outRef); }
  733.  
  734.     /* 3.) loop through the items
  735.      */
  736.     max = CountTDItems(h);
  737.     for(i = 1, j = 1 ; i <= max && noErr == errCode; i++){
  738.         NumToString(j, nS);
  739.         GetTDItem(h, i, inRes, itemS);
  740.         if(NOT (IsSkipItem(itemS))){
  741.             errCode = WriteStrItem(itemS, dlogS, helpStrsS, nS, outRef);
  742.             j++;
  743.         }
  744.     }
  745.  
  746.     /* 4.) dump out the medial header
  747.      */
  748.     if(noErr == errCode){ errCode = WriteStrSharp(kHDLGMedialStrs, dlogS, helpStrsS, nS, outRef); }
  749.  
  750.     /* 5.) loop through the items
  751.      */
  752.     for(i = 1, j = 1; i <= max && noErr == errCode; i++){
  753.         NumToString(j, nS);
  754.         GetTDItem(h, i, inRes, itemS);
  755.         errCode = WriteHdlgDitlItem(itemS, dlogS, helpStrsS, nS, outRef);
  756.         if(NOT (IsSkipItem(itemS))){
  757.             j++;
  758.         }
  759.     }
  760.  
  761.     /* 6.) dump out the closer.
  762.      */
  763.     if(noErr == errCode){ errCode = WriteStrSharp(kHDLGCloseStrs, dlogS, helpStrsS, nS, outRef); }
  764.     return errCode;
  765. }
  766.  
  767.  
  768. /* BalloonifyDialogs - for each DITL, write the ditl's STR#, write the ditl's 'hdlg'
  769.     this sorts the ditls.
  770.  */
  771. static OSErr BalloonifyDialogs(Integer inRes, Integer outRef){
  772.     OSErr    errCode;
  773.     Integer    i, max;
  774.     Integer saveResFile;
  775.     Handle    h;
  776.     SortResHandle    srh;
  777.  
  778.     errCode = noErr;
  779.     saveResFile = CurResFile();
  780.     UseResFile(inRes);
  781.  
  782.     /* get the sorted resources.
  783.      */
  784.     if(noErr != (errCode = NewSortedRes('DITL', &srh))){
  785.         return errCode;
  786.     }
  787.     max = GetHandleSize((Handle) srh) / sizeof(SortResRec);
  788.  
  789.  
  790.     /* process the sorted ditls.
  791.      */
  792.     for(i = 0; i < max && noErr == errCode ; i++){
  793.         h = (*srh)[i].h;
  794.         LoadResource(h);
  795.         if(noErr != (errCode = ResError())){
  796.             break;
  797.         }
  798.         HNoPurge(h);
  799.         HLock(h);
  800.         UseResFile(saveResFile);
  801.         errCode = BalloonifyDitl1(h, inRes, outRef);
  802.         UseResFile(inRes);
  803.         ReleaseResource(h);
  804.     }
  805.     UseResFile(saveResFile);
  806.     if(NIL != srh){
  807.         DisposeHandle((Handle) srh);
  808.     }
  809.     return errCode;
  810. }
  811.  
  812.  
  813. /* Balloonify - 
  814.     Note: what if we attempt to open ourself?
  815.  */
  816. OSErr Balloonify(FSSpecPtr fs, ScriptCode script){
  817.     OSErr    errCode;
  818.     Integer    res, outRefNum;
  819.     Integer saveResFile;
  820.     FSSpec    outFileSpec;
  821.     Str255    suffixS, creatorS, typeS;
  822.     OSType    creator, type;
  823.  
  824.     errCode = noErr;
  825.     saveResFile = CurResFile();
  826.     outRefNum = -1;
  827.     GetIndString(suffixS, kMainStrs, kSuffixS);
  828.     GetIndString(creatorS, kMainStrs, kCreatorS);
  829.     GetIndString(typeS, kMainStrs, kTypeS);
  830.     BlockMove(&creatorS[1], &creator, sizeof(OSType));
  831.     BlockMove(&typeS[1], &type, sizeof(OSType));
  832.  
  833.     /* Open the input file.
  834.      */
  835.     if(-1 == (res = FSpOpenResFile(fs, fsRdPerm))){
  836.         errCode = ResError();
  837.     }
  838.  
  839.     /* Create the output file
  840.      */
  841.     if(noErr == errCode){
  842.         UseResFile(saveResFile);
  843.         outFileSpec = *fs;
  844.         if(Length(outFileSpec.name) > 31 - Length(suffixS)){
  845.             outFileSpec.name[0] = 31 - Length(suffixS);
  846.         }
  847.         Concat(outFileSpec.name, suffixS);
  848.         errCode = FSpCreate(&outFileSpec, creator, type, script);
  849.     }
  850.  
  851.     /* open the output file.
  852.      */
  853.     if(noErr == errCode){
  854.         errCode = FSpOpenDF(&outFileSpec, fsWrPerm, &outRefNum);
  855.     }
  856.     if(noErr == errCode){
  857.         errCode = BalloonifyHeader(outFileSpec.name, outRefNum);
  858.     }
  859.     if(noErr == errCode){
  860.         StartProgress();
  861.         errCode = BalloonifyMenus(res, outRefNum);
  862.     }
  863.     if(noErr == errCode){
  864.         errCode = BalloonifyDialogs(res, outRefNum);
  865.     }
  866.     StopProgress();    /* safe to call even if StartProgress never called */
  867.  
  868.     /* close the output file. 
  869.         if an error occurred, delete the output file, if we created and opened it.
  870.      */
  871.     if(-1 != outRefNum){
  872.         if(noErr == errCode){ 
  873.             errCode = FSClose(outRefNum);
  874.         }else{
  875.             FSClose(outRefNum);
  876.         }
  877.         if(noErr == errCode){
  878.             errCode = FlushVol(NIL, outFileSpec.vRefNum);
  879.         }else{
  880.             FlushVol(NIL, outFileSpec.vRefNum);
  881.         }
  882.         if(noErr != errCode){    /* if an error occurred, delete the output file */
  883.             FSpDelete(&outFileSpec);
  884.         }
  885.     }
  886.  
  887.     /* close the input file.
  888.      */
  889.     if(-1 != res){
  890.         CloseResFile(res);
  891.         if(noErr == errCode){
  892.             errCode = ResError();
  893.         }
  894.     }
  895.     return errCode;
  896. }
  897.